package com.skiving.cloud.workflow.controller;

import com.mybatisflex.core.paginate.Page;
import com.skiving.cloud.auth.entity.AuthUser;
import com.skiving.cloud.auth.logutils.OperateLog;
import com.skiving.cloud.auth.util.UserUtil;
import com.skiving.cloud.common.exception.BusinessException;
import com.skiving.cloud.common.utils.PageParameter;
import com.skiving.cloud.common.utils.ReturnT;
import com.skiving.cloud.workflow.constants.WorkflowConstants;
import com.skiving.cloud.workflow.entity.ProcessDefinitionEntity;
import com.skiving.cloud.workflow.entity.ProcessXmlVo;
import com.skiving.cloud.workflow.service.ModelService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.noear.solon.Utils;
import org.noear.solon.annotation.*;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.DownloadedFile;
import org.noear.solon.core.handle.UploadedFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

/**
 * 流程模型设计
 * @author hushouquan
 */
@Controller
@Api("流程模型设计")
@Mapping(WorkflowConstants.WORKFLOW_BASE_URL +"/model")
public class ModelController{
    protected static final Logger log = LoggerFactory.getLogger(ModelController.class);
    
    @Inject
    private ModelService modelService;
    
    /**
     * 查询模型列表
     * @param parameter 参数
     * @return 分页信息
     */
    @Post
    @Mapping("/list")
    @ApiOperation("分页查询通用业务数据表(业务的表单数据）")
    public ReturnT<Page<ProcessDefinitionEntity>> list(@Body @Param("分页信息") PageParameter<Map<String, Object>> parameter) {
        AuthUser user = UserUtil.getCurrentUser();
        Page<ProcessDefinitionEntity> pageUtil = modelService.list(parameter, user);
        return ReturnT.ok(pageUtil);
    }
    
    /**
     * 根据id获取流程文件xml
     * @param id 流程定义id
     * @return 流程文件xml
     */
    @Get
    @Mapping("/getResourceByDefId/{id}")
    @ApiOperation("根据id获取流程文件xml")
    public ReturnT<String> getResourceByDefId(@Path(name="id") String id){
        try{
            String resourceXml = modelService.getResourceByDefId(id);
            return ReturnT.ok(resourceXml);
        }catch(Exception e){
            log.error("获取流程文件内容失败", e);
            return ReturnT.error();
        }
    }
    
    /**
     * 发布流程
     * @param id 流程定义id
     * @return 结果
     */
    @ApiOperation("发布模型")
    @Get
    @Mapping("/deploy/{id}")
    @OperateLog(module="流程管理-流程模型管理", description = "发布模型")
    public ReturnT<String> deploy(@Path("id") String id) {
        try {
            AuthUser user = UserUtil.getCurrentUser();
            modelService.deploy(id, user);
            return ReturnT.ok();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ReturnT.error(e.getMessage());
        }
    }
    
    /**
     * 保存流程设计
     * @param xmlVo 流程设计内容
     * @return 保存状况
     */
    @Post
    @Mapping("/saveProcessDefinition")
    @ApiOperation("保存流程设计")
    @OperateLog(module="流程管理-流程模型管理", description = "保存流程设计")
    public ReturnT<String> saveProcessDefinition(@Body ProcessXmlVo xmlVo){
        try {
            AuthUser user = UserUtil.getCurrentUser();
            modelService.saveProcessDefinition(xmlVo, user);
            return ReturnT.ok();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ReturnT.error(e.getMessage());
        }
    }
    
    /**
     * 查询模型历史记录列表
     * @param parameter 参数
     * @return 分页信息
     */
    @Post
    @Mapping("/getModelDeployHisList")
    @ApiOperation("查询模型历史记录列表")
    public  ReturnT<Page<ProcessDefinitionEntity>> getModelDeployHisList(@Body @Param("分页信息") PageParameter<Map<String, Object>> parameter) {
        if(!parameter.getParam().containsKey("key") || Utils.isBlank(parameter.getParam().get("key").toString())){
            return ReturnT.error("需要传入流程定义编号");
        }
        Page<ProcessDefinitionEntity> pageUtil = modelService.getModelDeployHisList(parameter);
        return ReturnT.ok(pageUtil);
    }
    
    /**
     * 根据部署id获取流程定义
     * @param deploymentId 流程部署id
     * @return 流程定义
     */
    @Get
    @Mapping("/getProcessDefinition/{deploymentId}")
    @ApiOperation("根据部署id获取流程定义")
    public ReturnT<ProcessDefinitionEntity> getProcessDefinition(@Path(name="deploymentId") String deploymentId){
        try{
            ProcessDefinition m = modelService.getProcessDefinitionByDeploymentId(deploymentId);
            ProcessDefinitionEntity p = new ProcessDefinitionEntity();
            p.setId(m.getId());
            p.setName(m.getName());
            p.setDescription(m.getDescription());
            p.setKey(m.getKey());
            p.setVersion(m.getVersion());
            p.setCategory(m.getCategory());
            p.setDeploymentId(m.getDeploymentId());
            p.setResourceName(m.getResourceName());
            p.setDiagramResourceName(m.getDiagramResourceName());
            p.setHasStartFormKey(m.hasStartFormKey());
            p.setTenantId(m.getTenantId());
            p.setVersionTag(m.getVersionTag());
            p.setHistoryTimeToLive(m.getHistoryTimeToLive());
            p.setStartableInTasklist(m.isStartableInTasklist());
            return ReturnT.ok(p);
        }catch(Exception e){
            log.error("获取流程定义失败", e);
            return ReturnT.error();
        }
    }
    
    /**
     * 导出流程文件
     * @param deploymentId 部署id
     * @return 返回
     */
    @Mapping(value = "/export/{deploymentId}")
    @ApiOperation("导出流程文件")
    public ReturnT<String> resourceRead(@Path("deploymentId") String deploymentId, Context ctx) {
        try {
            ProcessDefinition processDefinition = modelService.getProcessDefinitionByDeploymentId(deploymentId);
            
            if (processDefinition != null) {
                InputStream resourceAsStream = modelService.resourceRead(processDefinition.getId());
                //输出的文件名，可以自己指定
                DownloadedFile file = new DownloadedFile("application/octet-stream;charset=UTF-8", resourceAsStream, processDefinition.getResourceName());
                ctx.headerAdd("Pargam", "no-cache");
                ctx.headerAdd("Cache-Control", "no-cache");
                ctx.headerAdd("Content-Disposition", "attachment;filename=" + java.net.URLEncoder.encode(processDefinition.getResourceName(), StandardCharsets.UTF_8));
                ctx.outputAsFile(file);
            } else {
                return ReturnT.error("导出失败");
            }
            
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ReturnT.error("导出失败");
        }
        return null;
    }
    
    /**
     * 删除一个模型
     * @param id 流程定义id
     * @return 删除结果
     */
    @Get
    @Mapping("/delete/{id}")
    @ApiOperation("删除一个模型")
    @OperateLog(module="流程管理-流程模型管理", description = "删除流程模型")
    public ReturnT<String> remove(@Path("id") String id) {
        try {
            modelService.deleteModel(id);
            return ReturnT.ok("删除成功");
        } catch (Exception e) {
            log.error("删除模型失败", e);
            return ReturnT.error("删除失败");
        }
    }
    
    /**
     * 流程导入
     * @param ctx ctx
     * @return 结果
     */
    @Post
    @Mapping("/uploadModelFile")
    @ApiOperation("流程导入")
    @OperateLog(module="流程管理-流程模型管理", description = "导入流程")
    public ReturnT<String> uploadModelFile(Context ctx) {
        UploadedFile[] files= ctx.fileValues("file");
        AuthUser user = UserUtil.getCurrentUser();
        try {
            modelService.importDeploy(List.of(files), user);
            return ReturnT.ok("导入成功");
        } catch (BusinessException e){
            return ReturnT.error(e.getMessage());
        } catch (Exception e) {
            log.error("部署失败", e);
            return ReturnT.error("部署失败！");
        }
    }
    
    /**
     * 获取流程信息
     * @return {code:,message:,data:{key:流程定义编码,value:流程名称}}
     */
    @Get
    @Mapping("/getProcessDefKV")
    @ApiOperation("获取流程信息")
    public ReturnT<List<Map<String, String>>> getProcessDefKV() {
        List<Map<String, String>> list = modelService.getProcessDefKV();
        return ReturnT.ok(list);
    }

    /**
     * 获取所有流程定义
     * @return 流程目录
     */
    @Get
    @Mapping("/getAllProcessDefinitionEntity")
    @ApiOperation("获取所有流程定义")
    public ReturnT<List<ProcessDefinitionEntity>> getAllProcessDefinitionEntity() {
        return ReturnT.ok(modelService.getAllProcessDefinitionEntity());
    }
}
